#pragma once
#include "Requestor.hpp"

namespace zgwrpc
{
    namespace client
    {
        class RpcCaller
        {
        public:
            RpcCaller(Requestor::ptr requestor)
                : _requestor(requestor)
            {
            }
            using ptr = std::shared_ptr<RpcCaller>;
            using JsonAsyncResponse = std::future<Json::Value>;
            using JsonCallbackResponse = std::function<void(const Json::Value &)>;

            // 同步调用
            bool call(const BaseConnection::ptr &conn, const string &method, const Json::Value &params, Json::Value &result)
            {
                auto req_msg = MessageFactory::create<RpcRequest>();
                req_msg->setId(Uuid::Getid());
                req_msg->setMType(MType::REQ_RPC);
                req_msg->setMethod(method);
                req_msg->setParams(params);

                BaseMessage::ptr rsp_msg;

                bool ret = _requestor->Send(conn, req_msg, rsp_msg);
                if (ret == false)
                {
                    LOG(LogLevel::ERROR) << "RPC请求失败";
                    return false;
                }
                RpcResponse::ptr rpc_rsp_msg = dynamic_pointer_cast<RpcResponse>(rsp_msg);
                if (rpc_rsp_msg.get() == nullptr)
                {
                    LOG(LogLevel::ERROR) << "RPC响应消息类型错误";
                    return false;
                }
                if (rpc_rsp_msg->rCode() != RCode::RCODE_OK)
                {
                    LOG(LogLevel::ERROR) << "RPC响应消息错误码:";
                    return false;
                }
                result = rpc_rsp_msg->result();
                return true;
            }

            // 异步调用
            bool call(const BaseConnection::ptr &conn, const string &method, const Json::Value &params, std::future<Json::Value> &result)
            {
                auto req_msg = MessageFactory::create<RpcRequest>();
                req_msg->setId(Uuid::Getid());
                req_msg->setMType(MType::REQ_RPC);
                req_msg->setMethod(method);
                req_msg->setParams(params);

                auto json_promise = std::make_shared<std::promise<Json::Value>>();
                result = json_promise->get_future();
                Requestor::RequestCallback cb = std::bind(&RpcCaller::CallBack, this, json_promise, std::placeholders::_1);
                BaseMessage::ptr rsp_msg;

                bool ret = _requestor->Send(conn, req_msg, cb);
                if (ret == false)
                {
                    LOG(LogLevel::ERROR) << "RPC请求失败";
                    return false;
                }
                return true;
            }

            bool call(const BaseConnection::ptr&conn,const string &method, const Json::Value &params, const JsonCallbackResponse &callback)
            {
                auto req_msg = MessageFactory::create<RpcRequest>();
                req_msg->setId(Uuid::Getid());
                req_msg->setMType(MType::REQ_RPC);
                req_msg->setMethod(method);
                req_msg->setParams(params);
                Requestor::RequestCallback cb = std::bind(&RpcCaller::CallBack1, this, callback, std::placeholders::_1);

                bool ret = _requestor->Send(conn, req_msg, cb);
                if (ret == false)
                {
                    LOG(LogLevel::ERROR) << "RPC请求失败";
                    return false;
                }
                return true;
            }

        private:
            void CallBack1(const JsonCallbackResponse &callback, const BaseMessage::ptr &msg)
            {
                auto rpc_rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);
                if (!rpc_rsp_msg)
                {
                    LOG(LogLevel::ERROR) << "RPC响应，向下转型失败";
                    return;
                }
                if (rpc_rsp_msg->rCode() != RCode::RCODE_OK)
                {
                    LOG(LogLevel::ERROR) << "RPC响应消息错误码:";
                    return;
                }
                callback(rpc_rsp_msg->result());
            }
            
            //同步rpc
            void CallBack(std::shared_ptr<std::promise<Json::Value>> &result, const BaseMessage::ptr &msg)
            {
                auto rsp_msg = std::dynamic_pointer_cast<RpcResponse>(msg);
                if (!rsp_msg)
                {
                    LOG(LogLevel::ERROR) << "RPC响应，向下转型失败";
                    return;
                }
                if (rsp_msg->rCode() != RCode::RCODE_OK)
                {
                    LOG(LogLevel::ERROR) << "RPC响应消息错误码:";
                    return;
                }
                result->set_value(rsp_msg->result());
            }

        private:
            Requestor::ptr _requestor;
        };
    }
}